
#ifndef FIBER_ENV_FIBER_ENV_H_
#define FIBER_ENV_FIBER_ENV_H_

#include "./abs-time.h"
#include "./condition.h"
#include "./event.h"
#include "./fiber.h"
#include "./file.h"
#include "./mutex.h"
#include "./queue.h"
#include "./rwlock.h"
#include "./semaphore.h"
#include "./socket.h"

#include <stdio.h>

namespace fasmio { namespace fiber_env {

    class FiberEnv;
    FiberEnv* NewFiberEnv();


    // following functions are only available when invoking from the running fibers

    ITCPSocket* NewTCPSocket();
    IFile*      NewFile();
    IMutex*     NewMutex(bool recursive = false);
    IRWLock*    NewRWLock();
    ICondition* NewCondition(IMutex *mutex);
    IEvent*     NewEvent(bool init_state = false);
    ISemaphore* NewSemaphore(unsigned int max_count, unsigned int init_count = 0);

    void Sleep(unsigned long milliseconds);
    void Yield();
    void Quit(int quit_code);

    void NotifyToStop();

    Fiber* CreateFiber(int (*func)(void*), void* arg, const char* name = nullptr);
    Fiber* SelfFiber();

    void DumpFibers(FILE* fp);


    // class FiberEnv, member functions are accessible from outside fibers

    class FiberEnv
    {
    public:
        virtual ~FiberEnv() {};

    public:
        enum
        {
            THREADS_DEFAULT = 0xFFFFFFFF,
        };

    public:
        // Start the FiberEnv.  If 'threads' is THREADS_DEFAULT then FiberEnv
        // will decide how many worker threads will be created.  If 'threads'
        // is ZERO then the caller is responsible for calling FiberizeThisThread
        // in threads it created (or the main thread).
        virtual bool Start(unsigned int threads = THREADS_DEFAULT) = 0;

        // Notify FiberEnv to stop, can call inside a fiber.
        // Caller is responsible for the quiting of all the fibers.
        // Caller is still need to call Stop to recycle all resource.
        virtual bool NotifyToStop() = 0;

        // Notify and wait for FiberEnv to stop, cannot call inside a fiber.
        // Caller is responsible for the quiting of all the fibers.
        virtual bool Stop() = 0;

        virtual Fiber* CreateFiber(int (*func)(void*), void* arg, const char* name = nullptr) = 0;

        // Fiberize the current thread, cannot call inside a fiber, this function call will not
        // return until the FiberEnv is stopped (by NotifyToStop/Stop)
        virtual bool FiberizeThisThread() = 0;

        virtual void DumpFibers(FILE* fp) = 0;
    };

}}  // namespace fasmio::fiber_env

#endif  // FIBER_ENV_FIBER_ENV_H_

